package io.elegant.sessions

import android.content.Context
import com.google.protobuf.Any
import com.sscn.tts.SystemTtsEngine
import io.elegant.Elegant
import io.elegant.ElegantApiGrpc.ElegantApiStub
import io.elegant.toAny
import io.elegant.toStringValue
import io.grpc.stub.StreamObserver
import kotlinx.coroutines.launch

class TextToSpeechSession(
    stub: ElegantApiStub,
    private val context: Context
): BaseSession(stub, context) {
    override val sendStreamObserver: StreamObserver<Elegant.Interaction> = stub.textToSpeech(receiveStreamObserver)
    private var tts: SystemTtsEngine? = null
    override fun onCreate(sessionId: Long, futureId: Long, vararg argv: Any) {
        tts = SystemTtsEngine(context) {
            csMain.launch {
                argv[0].sendCallback()
            }
        }
        super.onCreate(sessionId, futureId, *argv)
    }
    override fun onDestroy() {
        tts?.release()
        super.onDestroy()
    }
    override suspend fun onReceive(name: String, sessionId: Long, futureId: Long, vararg argv: Any) {
        when (name) {
            "speak" -> speak(*argv)
            "stop" -> stop()
            "setOnStartListener" -> setOnStartListener(*argv)
            "setOnStopListener" -> setOnStopListener(*argv)
            "setOnDoneListener" -> setOnDoneListener(*argv)
            "setOnErrorListener" -> setOnErrorListener(*argv)
            else -> super.onReceive(name, sessionId, futureId, *argv)
        }
    }
    private fun setOnErrorListener(vararg argv: Any) = tts?.setOnErrorListener { utteranceId, errorCode ->
        csMain.launch {
            argv[0].sendCallback(utteranceId.toAny(), errorCode.toAny())
        }
    }
    private fun setOnDoneListener(vararg argv: Any) = tts?.setOnDoneListener {
        csMain.launch {
            argv[0].sendCallback(it.toAny())
        }
    }
    private fun setOnStartListener(vararg argv: Any) = tts?.setOnStartListener {
        csMain.launch {
            argv[0].sendCallback(it.toAny())
        }
    }
    private fun setOnStopListener(vararg argv: Any) = tts?.setOnStopListener { utteranceId, interrupted ->
        csMain.launch {
            argv[0].sendCallback(utteranceId.toAny(), interrupted.toAny())
        }
    }
    private fun speak(vararg argv: Any) {
        if (argv.isEmpty())
            throw IllegalArgumentException("Missing param `text` from the server calling this `speak` method.")
        val text = argv[0].toStringValue()
        val utteranceId = if (argv.size > 1) argv[1].toStringValue() else ""
        tts?.speak(text, utteranceId)
    }
    private fun stop() = tts?.stop()

}